/**
 ******************************************************************************
 * @file           : log.c
 * @brief          : MicroLog - Lightweight logging library implementation
 * @version        : 1.1.0
 * @date           : 2025-10-18
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "log.h"
#include "log_port.h"
#include <stdio.h>
#include <string.h>

/* Private typedef -----------------------------------------------------------*/
/**
 * @brief 模块标签过滤器结构体
 */
typedef struct {
    uint8_t level;                  /*!< 日志级别 */
    char tag[LOG_MAX_TAG_LENGTH];   /*!< 标签名称（空字符串表示未使用）*/
} log_tag_filter_t;

/**
 * @brief 日志配置结构体
 */
typedef struct {
    uint8_t global_level;           /*!< 全局日志级别 */
    size_t enabled_fmt_set[8];      /*!< 各级别的格式字段（8个级别：OFF-ALL）*/
    log_output_fn output_func;      /*!< 输出函数指针 */
    bool init_ok;                   /*!< 初始化完成标志 */
    bool output_enabled;            /*!< 输出使能标志 */
    log_tag_filter_t tag_filters[LOG_MAX_TAG_FILTERS];  /*!< 标签过滤器数组 */
} log_config_t;

/* Private variables ---------------------------------------------------------*/
/**
 * @brief 日志系统配置（静态全局变量）
 * 
 * @note  enabled_fmt_set 在 log_init() 中初始化
 */
static log_config_t sg_log = {
    .global_level = LOG_LEVEL_INFO,     /* 默认 INFO 级别 */
    .output_func = NULL,                /* NULL 则使用 printf */
    .init_ok = false,                   /* 未初始化 */
    .output_enabled = true              /* 默认启用输出 */
};

/**
 * @brief 级别名称字符串表（固定 5 字符对齐）
 */
static const char* const sg_level_names[] = {
    "OFF  ",    /* LOG_LEVEL_OFF (0) */
    "FATAL",    /* LOG_LEVEL_FATAL (1) */
    "ERROR",    /* LOG_LEVEL_ERROR (2) */
    "WARN ",    /* LOG_LEVEL_WARN (3) */
    "INFO ",    /* LOG_LEVEL_INFO (4) */
    "DEBUG",    /* LOG_LEVEL_DEBUG (5) */
    "TRACE",    /* LOG_LEVEL_TRACE (6) */
    "ALL  "     /* LOG_LEVEL_ALL (7) */
};

/**
 * @brief 全局日志行缓冲区
 * 
 * @note  所有日志输出共用此缓冲区，在输出前构建完整的日志行
 *        使用全局缓冲区避免栈溢出，特别是在中断上下文中调用时
 */
static char log_buf[LOG_MAX_LINE_LENGTH];

/* Private typedef -----------------------------------------------------------*/
/**
 * @brief 日志上下文结构体
 * 
 * @note  用于在格式化函数之间传递日志信息
 */
typedef struct {
    uint8_t level;          /*!< 日志级别 */
    const char *tag;        /*!< 模块标签 */
    const char *func;       /*!< 函数名（可为NULL）*/
    int line;               /*!< 行号（可为0）*/
} log_context_t;

/**
 * @brief 格式化函数指针类型
 * 
 * @param[out]  buf: 输出缓冲区
 * @param[in]   len: 缓冲区长度
 * @param[in]   ctx: 日志上下文
 * 
 * @return      写入的字符数
 */
typedef int (*format_func_t)(char *buf, int len, const log_context_t *ctx);

/* Private function prototypes -----------------------------------------------*/
/* 输出辅助函数 */
static void log_output_string(const char *str, size_t len);
static size_t log_strcpy(size_t cur_len, char *dst, const char *src);

/* 格式化函数 */
static int format_time(char *buf, int len, const log_context_t *ctx);
static int format_level(char *buf, int len, const log_context_t *ctx);
static int format_tag(char *buf, int len, const log_context_t *ctx);
static int format_task(char *buf, int len, const log_context_t *ctx);
static int format_func(char *buf, int len, const log_context_t *ctx);
static int format_line(char *buf, int len, const log_context_t *ctx);

/**
 * @brief 格式化函数映射表
 * 
 * @note  将格式字段与对应的格式化函数关联
 *        便于通过循环遍历的方式调用各个格式化函数
 */
static const struct {
    size_t fmt;                     /*!< 格式字段掩码 */
    format_func_t func;             /*!< 格式化函数指针 */
} sg_format_table[] = {
    {LOG_FMT_TIME,  format_time},   /* 时间戳 */
    {LOG_FMT_LVL,   format_level},  /* 日志级别 */
    {LOG_FMT_TAG,   format_tag},    /* 模块标签 */
    {LOG_FMT_TASK,  format_task},   /* 任务信息 */
    {LOG_FMT_FUNC,  format_func},   /* 函数名 */
    {LOG_FMT_LINE,  format_line},   /* 行号 */
};

/* Private functions ---------------------------------------------------------*/
/**
 * @brief       安全字符串复制
 *
 * @param[in]   cur_len: 目标缓冲区当前已写入长度
 * @param[out]  dst: 目标缓冲区指针（当前写入位置）
 * @param[in]   src: 源字符串指针
 *
 * @return      实际复制的字符数
 *
 * @note        自动检查缓冲区边界，防止溢出
 *              当达到LOG_MAX_LINE_LENGTH时自动停止复制
 */
static size_t log_strcpy(size_t cur_len, char *dst, const char *src)
{
    const char *src_old = src;
    
    LOG_ASSERT(dst != NULL);
    LOG_ASSERT(src != NULL);
    
    /* 逐字节复制，同时检查缓冲区边界 */
    while (*src != 0)
    {
        if (cur_len++ < LOG_MAX_LINE_LENGTH)
        {
            *dst++ = *src++;
        }
        else
        {
            break;  /* 已达到缓冲区边界 */
        }
    }
    
    return src - src_old;
}

/**
 * @brief       输出字符串
 *
 * @param[in]   str: 字符串
 * @param[in]   len: 字符串长度
 *
 * @retval      None
 *
 * @note        实际输出接口，支持指定长度的字符串输出
 */
static void log_output_string(const char *str, size_t len)
{
    /* 优先使用用户自定义输出函数 */
    if (sg_log.output_func != NULL)
    {
        sg_log.output_func(str, len);
        return;
    }
    
    /* 调用底层输出接口 */
    log_port_output(str, len);
}

/**
 * @brief       格式化时间戳
 *
 * @param[out]  buf: 输出缓冲区
 * @param[in]   len: 缓冲区长度
 * @param[in]   ctx: 日志上下文
 *
 * @return      写入的字符数
 */
static int format_time(char *buf, int len, const log_context_t *ctx)
{
    (void)ctx;  /* 未使用 */
    
#if LOG_ENABLE_TIMESTAMP
    uint32_t ms = log_port_get_tick();
    uint32_t seconds = ms / 1000;
    uint32_t minutes = seconds / 60;
    uint32_t hours = minutes / 60;
    
    uint8_t h = hours % 24;
    uint8_t m = minutes % 60;
    uint8_t s = seconds % 60;
    
    return snprintf(buf, len, "[%02d:%02d:%02d] ", h, m, s);
#else
    return 0;
#endif
}

/**
 * @brief       格式化日志级别
 *
 * @param[out]  buf: 输出缓冲区
 * @param[in]   len: 缓冲区长度
 * @param[in]   ctx: 日志上下文
 *
 * @return      写入的字符数
 */
static int format_level(char *buf, int len, const log_context_t *ctx)
{
    return snprintf(buf, len, "[%s] ", sg_level_names[ctx->level]);
}

/**
 * @brief       格式化模块标签
 *
 * @param[out]  buf: 输出缓冲区
 * @param[in]   len: 缓冲区长度
 * @param[in]   ctx: 日志上下文
 *
 * @return      写入的字符数
 */
static int format_tag(char *buf, int len, const log_context_t *ctx)
{
    const char *tag = ctx->tag;
    
    if (tag == NULL)
    {
        tag = "NO_TAG";  /* 默认标签（传入NULL时的保护）*/
    }
    
    return snprintf(buf, len, "[%-8s] ", tag);
}

/**
 * @brief       格式化任务信息
 *
 * @param[out]  buf: 输出缓冲区
 * @param[in]   len: 缓冲区长度
 * @param[in]   ctx: 日志上下文
 *
 * @return      写入的字符数
 *
 * @note        FreeRTOS 环境下显示当前任务名，裸机环境返回 0（不输出）
 */
static int format_task(char *buf, int len, const log_context_t *ctx)
{
    (void)ctx;  /* 未使用 */
    
#if LOG_ENABLE_TASK
    const char *task_name = log_port_get_task_name();
    if (task_name != NULL && task_name[0] != '\0')
    {
        return snprintf(buf, len, "[%s] ", task_name);
    }
#endif
    
    /* 未启用任务信息或无法获取任务名，不输出 */
    return 0;
}

/**
 * @brief       格式化函数名
 *
 * @param[out]  buf: 输出缓冲区
 * @param[in]   len: 缓冲区长度
 * @param[in]   ctx: 日志上下文
 *
 * @return      写入的字符数
 *
 * @note        如果函数名为 NULL，返回 0（不输出）
 */
static int format_func(char *buf, int len, const log_context_t *ctx)
{
    /* 如果未启用函数名，ctx->func 将为 NULL */
    if (ctx->func == NULL)
    {
        return 0;  /* 不输出 */
    }
    
    return snprintf(buf, len, "%s() ", ctx->func);
}

/**
 * @brief       格式化行号
 *
 * @param[out]  buf: 输出缓冲区
 * @param[in]   len: 缓冲区长度
 * @param[in]   ctx: 日志上下文
 *
 * @return      写入的字符数
 *
 * @note        如果行号为 0，返回 0（不输出）
 */
static int format_line(char *buf, int len, const log_context_t *ctx)
{
    /* 如果未启用行号，ctx->line 将为 0 */
    if (ctx->line == 0)
    {
        return 0;  /* 不输出 */
    }
    
    return snprintf(buf, len, ":%d ", ctx->line);
}

/* Exported functions --------------------------------------------------------*/

/* 初始化与控制 --------------------------------------------------------------*/
/**
 * @brief       初始化日志系统
 *
 * @param       None
 *
 * @retval      None
 */
void log_init(void)
{
    /* 防止重复初始化 */
    if (sg_log.init_ok)
    {
        return;
    }
    
    /* 移植层初始化 */
    log_port_init();
    
    /* 初始化配置为默认值 */
    sg_log.global_level = LOG_LEVEL_INFO;
    sg_log.output_func = NULL;
    sg_log.output_enabled = true;
    
    /* 初始化各级别的默认格式（分级策略）*/
    sg_log.enabled_fmt_set[LOG_LEVEL_OFF]   = 0;                             /* OFF: 无输出 */
    sg_log.enabled_fmt_set[LOG_LEVEL_FATAL] = LOG_FMT_ALL;                   /* FATAL: 所有字段 */
    sg_log.enabled_fmt_set[LOG_LEVEL_ERROR] = LOG_FMT_LVL | LOG_FMT_TAG | LOG_FMT_TIME;  /* ERROR: 时间+级别+标签 */
    sg_log.enabled_fmt_set[LOG_LEVEL_WARN]  = LOG_FMT_LVL | LOG_FMT_TAG | LOG_FMT_TIME;  /* WARN: 时间+级别+标签 */
    sg_log.enabled_fmt_set[LOG_LEVEL_INFO]  = LOG_FMT_LVL | LOG_FMT_TAG | LOG_FMT_TIME;  /* INFO: 时间+级别+标签 */
    sg_log.enabled_fmt_set[LOG_LEVEL_DEBUG] = LOG_FMT_ALL;                   /* DEBUG: 所有字段 */
    sg_log.enabled_fmt_set[LOG_LEVEL_TRACE] = LOG_FMT_ALL;                   /* TRACE: 所有字段 */
    sg_log.enabled_fmt_set[LOG_LEVEL_ALL]   = LOG_FMT_ALL;                   /* ALL: 所有字段 */
    
    /* 清空所有标签过滤器 */
    memset(sg_log.tag_filters, 0, sizeof(sg_log.tag_filters));

    /* 标记为已初始化 */
    sg_log.init_ok = true;
}

/**
 * @brief       反初始化日志系统
 *
 * @param       None
 *
 * @retval      None
 * 
 * @note        释放日志系统占用的资源，调用移植层反初始化
 */
void log_deinit(void)
{
    /* 检查初始化状态 */
    if (!sg_log.init_ok)
    {
        return;  /* 未初始化，直接返回 */
    }
    
    /* 移植层反初始化 */
    log_port_deinit();
    
    /* 标记为未初始化 */
    sg_log.init_ok = false;
}

/* 全局级别控制 --------------------------------------------------------------*/
/**
 * @brief       设置全局日志级别
 *
 * @param[in]   level: 日志级别
 *
 * @retval      None
 */
void log_set_global_level(uint8_t level)
{
    LOG_ASSERT(level <= LOG_LEVEL_ALL);  /* 断言：级别必须有效 */
    
    sg_log.global_level = level;
}

/**
 * @brief       获取全局日志级别
 *
 * @return      当前全局日志级别
 */
uint8_t log_get_global_level(void)
{
    return sg_log.global_level;
}

/* 模块标签级别过滤 ----------------------------------------------------------*/
/**
 * @brief       设置模块标签的日志级别
 *
 * @param[in]   tag: 模块标签
 * @param[in]   level: 日志级别
 *
 * @retval      None
 */
void log_set_tag_level(const char *tag, uint8_t level)
{
    LOG_ASSERT(tag != NULL);              /* 断言：标签不能为空 */
    LOG_ASSERT(level <= LOG_LEVEL_ALL);   /* 断言：级别必须有效 */
    
    /* 查找是否已存在 */
    for (int i = 0; i < LOG_MAX_TAG_FILTERS; i++)
    {
        if (sg_log.tag_filters[i].tag[0] != '\0' &&
            strcmp(sg_log.tag_filters[i].tag, tag) == 0)
        {
            /* 更新现有 */
            sg_log.tag_filters[i].level = level;
            return;
        }
    }
    
    /* 找空位添加 */
    for (int i = 0; i < LOG_MAX_TAG_FILTERS; i++)
    {
        if (sg_log.tag_filters[i].tag[0] == '\0')
        {
            strncpy(sg_log.tag_filters[i].tag, tag, LOG_MAX_TAG_LENGTH - 1);
            sg_log.tag_filters[i].tag[LOG_MAX_TAG_LENGTH - 1] = '\0';
            sg_log.tag_filters[i].level = level;
            return;
        }
    }
    
    /* 没有空位，忽略 */
}

/**
 * @brief       获取模块标签的日志级别
 *
 * @param[in]   tag: 模块标签
 *
 * @return      模块日志级别，0 表示未设置
 */
uint8_t log_get_tag_level(const char *tag)
{
    /* 参数有效性检查 */
    if (tag == NULL)
    {
        return 0;  /* tag 为 NULL，返回 0 表示使用全局级别 */
    }
    
    for (int i = 0; i < LOG_MAX_TAG_FILTERS; i++)
    {
        if (sg_log.tag_filters[i].tag[0] != '\0' &&
            strcmp(sg_log.tag_filters[i].tag, tag) == 0)
        {
            return sg_log.tag_filters[i].level;
        }
    }
    
    return 0;  /* 未找到，返回 0 表示使用全局级别 */
}

/**
 * @brief       清除模块标签的日志级别
 *
 * @param[in]   tag: 模块标签
 *
 * @retval      None
 */
void log_clear_tag_level(const char *tag)
{
    /* 参数有效性检查 */
    if (tag == NULL)
    {
        return;
    }
    
    for (int i = 0; i < LOG_MAX_TAG_FILTERS; i++)
    {
        if (sg_log.tag_filters[i].tag[0] != '\0' &&
            strcmp(sg_log.tag_filters[i].tag, tag) == 0)
        {
            sg_log.tag_filters[i].tag[0] = '\0';  /* 清空标签 = 释放槽位 */
            return;
        }
    }
}

/**
 * @brief       清除所有模块标签的日志级别
 *
 * @param       None
 *
 * @retval      None
 */
void log_clear_all_tag_levels(void)
{
    memset(sg_log.tag_filters, 0, sizeof(sg_log.tag_filters));
}

/* 格式配置 ------------------------------------------------------------------*/
/**
 * @brief       设置指定级别的输出格式
 *
 * @param[in]   level: 日志级别（LOG_LEVEL_xxx）
 * @param[in]   set: 格式掩码（LOG_FMT_xxx 的组合）
 *
 * @retval      None
 *
 * @note        示例：log_set_fmt(LOG_LEVEL_ERROR, LOG_FMT_TIME | LOG_FMT_LVL | LOG_FMT_TAG)
 */
void log_set_fmt(uint8_t level, size_t set)
{
    LOG_ASSERT(level < 8);  /* 断言：级别索引必须在 0-7 范围内 */
    
    sg_log.enabled_fmt_set[level] = set;
}

/**
 * @brief       获取指定级别的输出格式
 *
 * @param[in]   level: 日志级别（LOG_LEVEL_xxx）
 *
 * @return      格式掩码
 */
size_t log_get_fmt(uint8_t level)
{
    LOG_ASSERT(level < 8);  /* 断言：级别索引必须在 0-7 范围内 */
    
    return sg_log.enabled_fmt_set[level];
}

/* 输出控制 ------------------------------------------------------------------*/
/**
 * @brief       设置自定义输出函数
 *
 * @param[in]   func: 输出函数指针
 *
 * @retval      None
 */
void log_set_output(log_output_fn func)
{
    sg_log.output_func = func;
}

/**
 * @brief       设置输出使能
 *
 * @param[in]   enabled: true-启用输出，false-禁用输出
 *
 * @retval      None
 */
void log_set_output_enabled(bool enabled)
{
    sg_log.output_enabled = enabled;
}

/**
 * @brief       获取输出使能状态
 *
 * @return      true-输出已启用，false-输出已禁用
 */
bool log_get_output_enabled(void)
{
    return sg_log.output_enabled;
}

/* 日志输出函数 --------------------------------------------------------------*/
/**
 * @brief       原始输出函数（不带格式）
 *
 * @param[in]   fmt: 格式化字符串
 * @param[in]   ...: 可变参数
 *
 * @retval      None
 */
void log_raw(const char *fmt, ...)
{
    LOG_ASSERT(fmt != NULL);    /* 断言：格式字符串不能为空 */
    
    /* 检查输出使能 */
    if (!sg_log.output_enabled)
    {
        return;
    }
    
    /* 输出锁定 */
#if LOG_ENABLE_OUTPUT_LOCK
    log_port_lock();
#endif
    
    va_list args;
    va_start(args, fmt);
    int written = vsnprintf(log_buf, LOG_MAX_LINE_LENGTH, fmt, args);
    va_end(args);
    
    /* 计算实际长度 */
    size_t log_len = (written > 0 && written < LOG_MAX_LINE_LENGTH) ? written : strlen(log_buf);
    log_output_string(log_buf, log_len);
    
    /* 输出解锁 */
#if LOG_ENABLE_OUTPUT_LOCK
    log_port_unlock();
#endif
}

/**
 * @brief       核心日志输出函数
 *
 * @param[in]   level: 日志级别
 * @param[in]   tag: 模块标签
 * @param[in]   func: 函数名（可为NULL）
 * @param[in]   line: 行号（可为0）
 * @param[in]   fmt: 格式化字符串
 * @param[in]   ...: 可变参数
 *
 * @retval      None
 */
void log_output(uint8_t level, const char *tag, const char *func, int line, const char *fmt, ...)
{
    LOG_ASSERT(level <= LOG_LEVEL_ALL);     /* 断言：级别必须有效 */
    LOG_ASSERT(fmt != NULL);                /* 断言：格式字符串不能为空 */
    
    /* 检查输出使能 */
    if (!sg_log.output_enabled)
    {
        return;
    }
    
    /* 级别过滤：模块级别优先于全局级别 */
    uint8_t tag_level = log_get_tag_level(tag);
    if (tag_level != 0)
    {
        /* 该模块设置了级别，使用模块级别（忽略全局）*/
        if (level > tag_level)
        {
            return;
        }
    }
    else
    {
        /* 该模块未设置，使用全局级别 */
        if (level > sg_log.global_level)
        {
            return;
        }
    }
    
    /* 输出锁定：保护多线程安全 */
#if LOG_ENABLE_OUTPUT_LOCK
    log_port_lock();
#endif
    
    /* 构建日志上下文 */
    log_context_t ctx = {
        .level = level,
        .tag = tag,
        .func = func,   /* 可能为 NULL */
        .line = line,   /* 可能为 0 */
    };
    
    /* 构建输出缓冲区（使用全局缓冲区）*/
    char *ptr = log_buf;
    int remaining = LOG_MAX_LINE_LENGTH;
    
    /* 获取当前级别的格式掩码 */
    size_t enabled_fmt = (level < 8) ? sg_log.enabled_fmt_set[level] : LOG_FMT_ALL;
    
    /* 遍历格式化表，根据掩码输出各字段 */
    for (size_t i = 0; i < sizeof(sg_format_table) / sizeof(sg_format_table[0]); i++)
    {
        if (enabled_fmt & sg_format_table[i].fmt)
        {
            int written = sg_format_table[i].func(ptr, remaining, &ctx);
            
            /* 安全检查：防止缓冲区溢出 */
            if (written > 0 && written < remaining)
            {
                ptr += written;
                remaining -= written;
            }
            else if (written >= remaining)
            {
                /* 缓冲区已满，截断 */
                ptr += remaining - 1;
                *ptr = '\0';
                remaining = 0;
                break;
            }
            
            if (remaining <= 0)
            {
                break;  /* 缓冲区已满 */
            }
        }
    }
    
    /* 用户消息 */
    if (remaining > 1)  /* 至少保留1字节给'\0' */
    {
        va_list args;
        va_start(args, fmt);
        int written = vsnprintf(ptr, remaining, fmt, args);
        va_end(args);
        
        /* 安全检查：vsnprintf 返回值处理 */
        if (written > 0)
        {
            if (written < remaining)
            {
                /* 正常情况 */
                ptr += written;
                remaining -= written;
            }
            else
            {
                /* 发生截断 */
                ptr += remaining - 1;
                remaining = 1;  /* 只剩下'\0'的空间 */
            }
        }
    }
    
    /* 换行符 */
    static const size_t newline_len = sizeof(LOG_NEWLINE) - 1;  /* 编译期计算长度 */
    if (remaining > (int)newline_len)
    {
        memcpy(ptr, LOG_NEWLINE, newline_len);
        ptr += newline_len;
        *ptr = '\0';
    }
    else if (remaining > 0)
    {
        *ptr = '\0';  /* 空间不足，至少保证字符串结束 */
    }
    
    /* 输出（传递实际长度）*/
    size_t log_len = ptr - log_buf;
    log_output_string(log_buf, log_len);
    
    /* 输出解锁 */
#if LOG_ENABLE_OUTPUT_LOCK
    log_port_unlock();
#endif
}

/**
 * @brief       HEX 数据输出函数
 *
 * @param[in]   level: 日志级别
 * @param[in]   tag: 模块标签
 * @param[in]   data: 数据指针
 * @param[in]   len: 数据长度
 *
 * @retval      None
 *
 * @note        输出格式：
 *              0000: 01 02 03 04 05 06 07 08  09 0A 0B 0C 0D 0E 0F 10  ................
 *              - 每行16字节
 *              - 每8字节添加额外空格分隔
 *              - 右侧显示对应的ASCII字符（不可打印字符显示为'.'）
 */
void log_hex_dump(uint8_t level, const char *tag, const void *data, uint16_t len)
{
#define __is_print(ch)  ((unsigned int)((ch) - ' ') < 127u - ' ')  /* 判断字符是否可打印 */

    LOG_ASSERT(level <= LOG_LEVEL_ALL);  /* 断言：级别必须有效 */
    LOG_ASSERT(data != NULL);            /* 断言：数据指针不能为空 */
    LOG_ASSERT(len > 0);                 /* 断言：长度必须大于0 */

    /* 检查输出使能 */
    if (!sg_log.output_enabled)
    {
        return;
    }
    
    /* 级别过滤：模块级别优先于全局级别 */
    uint8_t tag_level = log_get_tag_level(tag);
    if (tag_level != 0)
    {
        /* 该模块设置了级别，使用模块级别（忽略全局）*/
        if (level > tag_level)
        {
            return;
        }
    }
    else
    {
        /* 该模块未设置，使用全局级别 */
        if (level > sg_log.global_level)
        {
            return;
        }
    }
    
    /* 输出锁定：整个 HEX Dump 作为原子操作，防止多线程输出混乱 */
#if LOG_ENABLE_OUTPUT_LOCK
    log_port_lock();
#endif
    
    /* 类型转换，便于逐字节访问 */
    const uint8_t *buf_p = (const uint8_t *)data;
    
    /* 按行处理数据 */
    for (uint16_t i = 0; i < len; i += 16)
    {
        /* 封装头部信息（地址范围）*/
        int fmt_result = snprintf(log_buf, LOG_MAX_LINE_LENGTH, "%04X-%04X: ", i, i + 15);
        
        /* 计算日志长度 */
        uint16_t log_len;
        if ((fmt_result > -1) && (fmt_result <= LOG_MAX_LINE_LENGTH))
        {
            log_len = fmt_result;
        }
        else
        {
            log_len = LOG_MAX_LINE_LENGTH;
        }
        
        /* 转储十六进制数据 */
        char dump_string[8] = {0};
        for (uint16_t j = 0; j < 16; j++)
        {
            if (i + j < len)
            {
                snprintf(dump_string, sizeof(dump_string), "%02X ", buf_p[i + j]);
            }
            else
            {
                strncpy(dump_string, "   ", sizeof(dump_string));
            }
            log_len += log_strcpy(log_len, log_buf + log_len, dump_string);
            
            /* 每8个字节添加额外空格 */
            if ((j + 1) % 8 == 0)
            {
                log_len += log_strcpy(log_len, log_buf + log_len, " ");
            }
        }
        log_len += log_strcpy(log_len, log_buf + log_len, "  ");
        
        /* 转储对应的ASCII字符 */
        for (uint16_t j = 0; j < 16; j++)
        {
            if (i + j < len)
            {
                snprintf(dump_string, sizeof(dump_string), "%c", 
                        __is_print(buf_p[i + j]) ? buf_p[i + j] : '.');
                log_len += log_strcpy(log_len, log_buf + log_len, dump_string);
            }
        }
        
        /* 溢出检查并为换行符预留空间 */
        if (log_len + sizeof(LOG_NEWLINE) - 1 > LOG_MAX_LINE_LENGTH)
        {
            log_len = LOG_MAX_LINE_LENGTH - (sizeof(LOG_NEWLINE) - 1);
        }
        
        /* 封装换行符 */
        log_len += log_strcpy(log_len, log_buf + log_len, LOG_NEWLINE);
        
        /* 执行日志输出 */
        log_port_output(log_buf, log_len);
    }
    
    /* 输出解锁 */
#if LOG_ENABLE_OUTPUT_LOCK
    log_port_unlock();
#endif

#undef __is_print
}
